import java.lang.reflect.Array;
import java.net.*;
import java.util.ArrayList;
import java.io.*;

/**
 * @author Dennis Thomasen(whooper) & Nikolas Bram(Bram)
 * @studentId 20103903 				& 20104278 
 * @group 3
 * 
 */

public class Server implements Bank{

	protected int port = 40303;
	protected ServerSocket serverSocket; 
	private int currentID = -1;
	private ArrayList<AccountImpl> accounts = new ArrayList<AccountImpl>();

	// Find servers IP-address
	public void findLocalHost(){
		try {
			InetAddress localhost = InetAddress.getLocalHost();
			String localhostAddress = localhost.getHostAddress();
			System.out.println("[SERVER]> Server IP-address: "+ localhostAddress);
		} catch (UnknownHostException e) {
			System.err.println("[SERVER]> Cannot resolve the Internet address of the local host.");
			System.err.println(e);
			System.exit(-1);
		}
	}

	// The server will be bind to a given port
	public void bindToPort(){
		try {
			serverSocket = new ServerSocket(port);
			System.out.println("[SERVER]> Server port: "+ port);
		} catch (IOException e) {
			serverSocket = null;
			System.err.println("[SERVER]> Cannot open server socket on port number" + port);
			System.err.println(e);
			System.exit(-1);			
		}	
	}

	// Waiting for connection from client
	public Socket waitForConnection(){
		Socket socket = null;
		try{
			socket = serverSocket.accept();
		} catch(IOException e){}
		return socket;		
	}


	// Run on server startup
	public void run(){
		System.out.println("[SERVER]> Connecting...");

		findLocalHost();
		bindToPort();

		while(true){
			Socket socket = waitForConnection();
			if(socket != null){
				RequestThread requestThread = new RequestThread(socket);
				requestThread.start();
			}
		}
	}

	// inner class - thread handling
	public class RequestThread extends Thread{
		private Socket socket;

		public RequestThread (Socket socket) {
			this.socket = socket;
		}

		public void run() {
			System.out.println("[SERVER]> Request from: " + socket);
			try {
				BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
				DataOutputStream output = new DataOutputStream(socket.getOutputStream());

				httpHandler(input, output);

				output.close();
				input.close();
				socket.close();
			} catch (IOException e) {
				System.out.println(e);
			}
		}	 
	}

	// Making the header
	public String makeHeader(String filename, int responseCode){
		String header = null;
		header += "HTTP/1.0 ";

		switch(responseCode){
		case 200: 
			header += "200 OK"; break;
		case 404: 
			header += "404 Not Found"; break;
		}
		header += "\r\n";

		if(filename.endsWith(".jpg") || filename.endsWith(".jpeg")){
			header += "Content-Type: image/jpeg\r\n";
		}else if(filename.endsWith(".gif")){
			header += "Content-Type: image/gif\r\n";
		}else if(filename.endsWith(".txt")){
			header += "Content-Type: text/plain\r\n";
		}else if(filename.endsWith(".pdf")){
			header += "Contet-Type: application/pdf\r\n";
		}else{
			header += "Contet-Type: text/html\r\n";
		} 
		header += "\r\n";
		return header;		
	}

	//Handling the unique account ID
	public int getNextId(){
		currentID++;
		return currentID;
	}

	//Finding the nth occurence of a pattern in a string
	public static int nth(String source, String pattern, int n) {

		int i = 0, pos = 0, tpos = 0;

		while (i < n) {

			pos = source.indexOf(pattern);
			if (pos > -1) {
				source = source.substring(pos+1);
				tpos += pos+1;
				i++;
			} else {
				return -1;
			}
		}
		return tpos - 1;
	}

	// Handling the input from client
	public void httpHandler(BufferedReader input, DataOutputStream output) throws IOException{
		String request = input.readLine();
		if(request != null){
			int requestPart = request.indexOf(" ");
			String filename = request.substring(request.indexOf("/"), request.indexOf(" ", requestPart+1));

			System.out.println("[SERVER]> File requested: |"+ filename +"|");

			if(filename.equals("/")){
				filename = "index.html";
			}

			if(filename.indexOf("?") != -1){

				/**
				 * /Bank/getAccount?name=Bill_Gates
				 * /Account/0/getBalance?
				 */
				int requestPart2 = request.indexOf("/");
				String inputName = request.substring(request.indexOf("=")+1, request.indexOf("HTTP")-1);
				if(filename.substring(1,filename.indexOf("/",requestPart2+1)).equals("Bank")){
					if(accounts.size() == 0){
						accounts.add(new AccountImpl(inputName, getNextId()));
						printAccountInfo(getAccount(inputName), output); //Hvis account ikke eksisterer oprettes den og info om den nye account skrives ud
					}else{
						if(getAccount(inputName) == null){
							accounts.add(new AccountImpl(inputName, getNextId()));
							printAccountInfo(getAccount(inputName), output);
						}else{
							printAccountInfo(getAccount(inputName), output); //Hvis accounten eksisterer udskrives info om accounten
						}
					}
				}else if(filename.substring(1,filename.indexOf("/",requestPart2+1)).equals("Account")){
					int requestId = Integer.parseInt(request.substring(nth(request,"/",2)+1,nth(request,"/",3)));//Henter ID ud fra requesten
					for(int i=0; i<accounts.size(); i++){
						if(accounts.get(i).getId() == requestId){
							if(request.substring(nth(request,"/",3)+1, request.indexOf("?")).equals("getBalance")){
								printBalance(accounts.get(i).getBalance(),output);
							}
							if(request.substring(nth(request,"/",3)+1, request.indexOf("?")).equals("getName")){
								if(accounts.get(i).getId() == Integer.parseInt(request.substring(nth(request,"/",2)+1,nth(request,"/",3)))){
									printName(accounts.get(i).getName(), output);
								}
							}
							if(request.substring(nth(request,"/",3)+1, request.indexOf("?")).equals("deposit")){
								accounts.get(i).deposit(Double.parseDouble(request.substring(request.indexOf("=")+1, nth(request," ",2))));
								printBalance(accounts.get(i).getBalance(),output);
							}
							if(request.substring(nth(request,"/",3)+1, request.indexOf("?")).equals("withdraw")){
								accounts.get(i).withdraw(Double.parseDouble(request.substring(request.indexOf("=")+1, nth(request," ",2))));
								printBalance(accounts.get(i).getBalance(),output);
							}
						}
					}
				}else{
					
					InputStream requestFileInput;
					int responseCode;
					
					File requestedFile = new File("404.html");
					requestFileInput = new FileInputStream(requestedFile);
					responseCode = 404;
					
					
					// Header sent to client
					output.writeBytes(makeHeader(filename, responseCode));

					// Content sent to client
					while(true){
						int bit = requestFileInput.read();
						if(bit == -1)
							break;
						output.write(bit);
					}
				}

			} else {
				InputStream requestFileInput;
				int responseCode;

				try{
					File requestedFile = new File(filename);
					requestFileInput = new FileInputStream(requestedFile);
					responseCode = 200;
				} catch(FileNotFoundException e){
					File requestedFile = new File("404.html");
					requestFileInput = new FileInputStream(requestedFile);
					responseCode = 404;
				}



				// Header sent to client
				output.writeBytes(makeHeader(filename, responseCode));

				// Content sent to client
				while(true){
					int bit = requestFileInput.read();
					if(bit == -1)
						break;
					output.write(bit);
				}
				System.out.println("[SERVER]> Response sent to Client");	
			}
		}
	}

	//Printer Info om den paagaeldende account til browseren
	public void printAccountInfo(Account account,  DataOutputStream output) throws IOException{
		String responseFile = ""; 
		int responseCode;

		responseFile += "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>";
		responseFile +=	"<html xmlns='http://www.w3.org/1999/xhtml'xml:lang='en' lang='en'>";
		responseFile += "<head><title>Bank - Account</title></head>";
		responseFile += "<body>";
		responseFile += "<h1>Account Overview</h1>";
		responseFile += "<p>";
		responseFile += "<br />Konto navn:" + account.getName();
		responseFile += "<br />Konto id: " + account.getId();
		responseFile += "<br />Balance: " + account.getBalance();
		responseFile += "</p>";

		responseCode = 200;

		// Header sent to client
		output.writeBytes(makeHeader(responseFile, responseCode));

		// Content sent to client

		output.writeBytes(responseFile);

		System.out.println("[SERVER]> Response sent to Client");
	}

	//Printer balance til browseren
	public void printBalance(double balance, DataOutputStream output) throws IOException{
		String responseFile = ""; 
		int responseCode;

		responseFile += "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>";
		responseFile +=	"<html xmlns='http://www.w3.org/1999/xhtml'xml:lang='en' lang='en'>";
		responseFile += "<head><title>Bank - Account - Balance</title></head>";
		responseFile += "<body>";
		responseFile += "<h1>Account Balance</h1>";
		responseFile += "<p>";
		responseFile += "<br />Balance: " + balance +" DKK";
		responseFile += "</p>";

		responseCode = 200;

		// Header sent to client
		output.writeBytes(makeHeader(responseFile, responseCode));

		// Content sent to client

		output.writeBytes(responseFile);

		System.out.println("[SERVER]> Response sent to Client");
	}

	//Printer name til browseren
	public void printName(String name, DataOutputStream output) throws IOException{
		String responseFile = ""; 
		int responseCode;

		responseFile += "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>";
		responseFile +=	"<html xmlns='http://www.w3.org/1999/xhtml'xml:lang='en' lang='en'>";
		responseFile += "<head><title>Bank - Account - Balance</title></head>";
		responseFile += "<body>";
		responseFile += "<h1>Account name</h1>";
		responseFile += "<p>";
		responseFile += "<br />Name: " + name;
		responseFile += "</p>";

		responseCode = 200;

		// Header sent to client
		output.writeBytes(makeHeader(responseFile, responseCode));

		// Content sent to client

		output.writeBytes(responseFile);

		System.out.println("[SERVER]> Response sent to Client");
	}

	public Account getAccount(String name) {
		for(int i=0; i<accounts.size(); i++){
			if(accounts.get(i).getName().equals(name)){
				return accounts.get(i);
			}
		}
		return null;
	}
	
	// Main method
	public static void main(String[] args) throws IOException {
		Server server = new Server();
		server.run();
	}
}